home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / TCPUSER.C < prev    next >
Text File  |  1993-08-09  |  8KB  |  347 lines

  1. /* User calls to TCP */
  2. #include <stdio.h>
  3. #include "global.h"
  4. #include "timer.h"
  5. #include "mbuf.h"
  6. #include "netuser.h"
  7. #include "socket.h"
  8. #include "internet.h"
  9. #include "tcp.h"
  10. #include "ip.h"
  11. #include "icmp.h"
  12. #include "proc.h"
  13.  
  14. int16 Tcp_window = DEF_WND;
  15.  
  16. struct tcb *
  17. open_tcp(
  18. struct socket *lsocket,        /* Local socket */
  19. struct socket *fsocket,        /* Remote socket */
  20. int mode,                    /* Active/passive/server */
  21. int16 window,                /* Receive window (and send buffer) sizes */
  22. void (*r_upcall)(),            /* Function to call when data arrives */
  23. void (*t_upcall)(),            /* Function to call when ok to send more data */
  24. void (*s_upcall)(),            /* Function to call when connection state changes */
  25. int tos,
  26. int user)                    /* User linkage area */
  27. {
  28.     struct connection conn;
  29.     struct tcb *tcb;
  30.  
  31.     if(lsocket == NULLSOCK){
  32.         return NULLTCB;
  33.     }
  34.     conn.local.address = lsocket->address;
  35.     conn.local.port = lsocket->port;
  36.  
  37.     if(fsocket != NULLSOCK){
  38.         conn.remote.address = fsocket->address;
  39.         conn.remote.port = fsocket->port;
  40.     } else {
  41.         conn.remote.address = 0;
  42.         conn.remote.port = 0;
  43.     }
  44.     if((tcb = lookup_tcb(&conn)) == NULLTCB) {
  45.         if((tcb = create_tcb(&conn)) == NULLTCB) {
  46.             return NULLTCB;
  47.         }
  48.     } else if(tcb->state != TCP_LISTEN) {
  49.         return NULLTCB;
  50.     }
  51.     tcb->user = user;
  52.  
  53.     if(window != 0) {
  54.         tcb->window = tcb->rcv.wnd = window;
  55.     } else {
  56.         tcb->window = tcb->rcv.wnd = Tcp_window;
  57.     }
  58.     tcb->snd.wnd = 1;                /* Allow space for sending a SYN */
  59.     tcb->r_upcall = r_upcall;
  60.     tcb->t_upcall = t_upcall;
  61.     tcb->s_upcall = s_upcall;
  62.     tcb->tos = tos;
  63.  
  64.     switch(mode){
  65.     case TCP_SERVER:
  66.         tcb->flags.clone = 1;
  67.     case TCP_PASSIVE:    /* Note fall-thru */
  68.         setstate(tcb,TCP_LISTEN);
  69.         break;
  70.     case TCP_ACTIVE:
  71.         /* Send SYN, go into TCP_SYN_SENT state */
  72.         tcb->flags.active = 1;
  73.         send_syn(tcb);
  74.         setstate(tcb,TCP_SYN_SENT);
  75.         tcp_output(tcb);
  76.         break;
  77.     }
  78.     return tcb;
  79. }
  80.  
  81. /* User send routine */
  82. int
  83. send_tcp(struct tcb *tcb,struct mbuf *bp)
  84. {
  85.     int16 cnt = len_p(bp);
  86.  
  87.     if(tcb == NULLTCB || bp == NULLBUF) {
  88.         if(bp) {
  89.             free_p(bp);
  90.         }
  91.         return -1;
  92.     }
  93.  
  94.     switch(tcb->state){
  95.     case TCP_CLOSED:
  96.         free_p(bp);
  97.         return -1;
  98.     case TCP_LISTEN:
  99.         if(tcb->conn.remote.address == 0 && tcb->conn.remote.port == 0) {
  100.             /* Save data for later */
  101.             append(&tcb->sndq,bp);
  102.             tcb->sndcnt += cnt;
  103.             break;
  104.         }
  105.         /* Change state from passive to active */
  106.         tcb->flags.active = 1;
  107.         send_syn(tcb);
  108.         setstate(tcb,TCP_SYN_SENT);    /* Note fall-thru */
  109.     case TCP_SYN_SENT:
  110.     case TCP_SYN_RECEIVED:
  111.     case TCP_ESTABLISHED:
  112.     case TCP_CLOSE_WAIT:
  113.         append(&tcb->sndq,bp);
  114.         tcb->sndcnt += cnt;
  115.         tcp_output(tcb);
  116.         break;
  117.     case TCP_FINWAIT1:
  118.     case TCP_FINWAIT2:
  119.     case TCP_CLOSING:
  120.     case TCP_LAST_ACK:
  121.     case TCP_TIME_WAIT:
  122.         free_p(bp);
  123.         return -1;
  124.     }
  125.     return (int)cnt;
  126. }
  127.  
  128. /* User receive routine */
  129. int
  130. recv_tcp(struct tcb *tcb,struct mbuf **bpp,int16 cnt)
  131. {
  132.     if(tcb == NULLTCB || bpp == NULLBUFP) {
  133.         return -1;
  134.     }
  135.     if(tcb->rcvcnt == 0) {
  136.         /* If there's nothing on the queue, our action depends on what state
  137.          * we're in (i.e., whether or not we're expecting any more data).
  138.          * If no more data is expected, then simply return 0; this is
  139.          * interpreted as "end of file". Otherwise return -1.
  140.          */
  141.         switch(tcb->state) {
  142.         case TCP_LISTEN:
  143.         case TCP_SYN_SENT:
  144.         case TCP_SYN_RECEIVED:
  145.         case TCP_ESTABLISHED:
  146.         case TCP_FINWAIT1:
  147.         case TCP_FINWAIT2:
  148.             return -1;
  149.         case TCP_CLOSED:
  150.         case TCP_CLOSE_WAIT:
  151.         case TCP_CLOSING:
  152.         case TCP_LAST_ACK:
  153.         case TCP_TIME_WAIT:
  154.             *bpp = NULLBUF;
  155.             return 0;
  156.         }
  157.     }
  158.     /* cnt == 0 means "I want it all" */
  159.     if(cnt == 0) {
  160.         cnt = tcb->rcvcnt;
  161.     }
  162.     /* See if the user can take all of it */
  163.     if(tcb->rcvcnt <= cnt) {
  164.         cnt = tcb->rcvcnt;
  165.         *bpp = tcb->rcvq;
  166.         tcb->rcvq = NULLBUF;
  167.     } else {
  168.         *bpp = alloc_mbuf(cnt);
  169.         pullup(&tcb->rcvq,(*bpp)->data,cnt);
  170.         (*bpp)->cnt = cnt;
  171.     }
  172.     tcb->rcvcnt -= cnt;
  173.     tcb->rcv.wnd += cnt;
  174.  
  175.     /* Do a window update if it was closed */
  176.     if(cnt == tcb->rcv.wnd) {
  177.         tcb->flags.force = 1;
  178.         tcp_output(tcb);
  179.     }
  180.     return (int)cnt;
  181. }
  182.  
  183. /* This really means "I have no more data to send". It only closes the
  184.  * connection in one direction, and we can continue to receive data
  185.  * indefinitely.
  186.  */
  187. int
  188. close_tcp(struct tcb *tcb)
  189. {
  190.     if(tcpval(tcb)) {
  191.         switch(tcb->state){
  192.         case TCP_LISTEN:
  193.         case TCP_SYN_SENT:
  194.             close_self(tcb,NORMAL);
  195.         case TCP_CLOSED:
  196.             return 0;                        /* Unlikely */
  197.         case TCP_SYN_RECEIVED:
  198.         case TCP_ESTABLISHED:
  199.         case TCP_CLOSE_WAIT:
  200.             tcb->sndcnt++;
  201.             tcb->snd.nxt++;
  202.             setstate(tcb,tcb->state == TCP_CLOSE_WAIT ?    TCP_LAST_ACK : TCP_FINWAIT1);
  203.             tcp_output(tcb);
  204.             return 0;
  205.         case TCP_FINWAIT1:
  206.         case TCP_FINWAIT2:
  207.         case TCP_CLOSING:
  208.         case TCP_LAST_ACK:
  209.         case TCP_TIME_WAIT:
  210.             return -1;
  211.         }
  212.     }
  213.     return -1;    /* "Can't happen" */
  214. }
  215.  
  216. /* Delete TCB, free resources. The user is not notified, even if the TCB is
  217.  * not in the TCP_CLOSED state. This function should normally be called by the
  218.  * user only in response to a state change upcall to TCP_CLOSED state.
  219.  */
  220. int
  221. del_tcp(struct tcb *conn)
  222. {
  223.     struct tcb *tcb, *tcblast = NULLTCB;
  224.     struct reseq *rp, *rp1;
  225.  
  226.     for(tcb = Tcbs; tcb != NULLTCB; tcblast = tcb, tcb = tcb->next) {
  227.         if(tcb == conn) {
  228.             break;
  229.         }
  230.     }
  231.     if(tcb == NULLTCB) {
  232.         return -1;    /* conn was NULL, or not on list */
  233.     }
  234.     if(tcblast != NULLTCB) {
  235.         tcblast->next = tcb->next;
  236.     } else {
  237.         Tcbs = tcb->next;    /* was first on list */
  238.     }
  239.     stop_timer(&tcb->timer);
  240.  
  241.     for(rp = tcb->reseq; rp != NULLRESEQ; rp = rp1) {
  242.         rp1 = rp->next;
  243.         free_p(rp->bp);
  244.         xfree(rp);
  245.     }
  246.     tcb->reseq = NULLRESEQ;
  247.     free_p(tcb->rcvq);
  248.     free_p(tcb->sndq);
  249.     xfree(tcb);
  250.     return 0;
  251. }
  252.  
  253. /* Return 1 if arg is a valid TCB, 0 otherwise */
  254. int
  255. tcpval(struct tcb *tcb)
  256. {
  257.     if(tcb != NULLTCB) {
  258.         struct tcb *tcb1;
  259.  
  260.         for(tcb1 = Tcbs; tcb1 != NULLTCB; tcb1 = tcb1->next) {
  261.             if(tcb1 == tcb) {
  262.                 return 1;
  263.             }
  264.         }
  265.     }
  266.     return 0;
  267. }
  268.  
  269. /* Kick a particular TCP connection */
  270. int
  271. kick_tcp(struct tcb *tcb)
  272. {
  273.     if(!tcpval(tcb)) {
  274.         return -1;
  275.     }
  276.     tcb->flags.force = 1;
  277.     tcp_timeout(tcb);
  278.     return 0;
  279. }
  280.  
  281. /* Kick all TCP connections to specified address; return number kicked */
  282. int
  283. kick(int32 addr)
  284. {
  285.     struct tcb *tcb;
  286.     int cnt = 0;
  287.  
  288.     for(tcb = Tcbs; tcb != NULLTCB; tcb = tcb->next) {
  289.         if(tcb->conn.remote.address == addr) {
  290.             kick_tcp(tcb);
  291.             cnt++;
  292.         }
  293.     }
  294.     return cnt;
  295. }
  296.  
  297. /* Clear all TCP connections */
  298. void
  299. reset_all(void)
  300. {
  301.     struct tcb *tcb, *tcbtmp = NULLTCB;
  302.  
  303.     for(tcb = Tcbs; tcb != NULLTCB; tcb = tcbtmp) {
  304.         int flag = 0;
  305.         tcbtmp = tcb->next;
  306.  
  307.         if(tcb->conn.local.address == Ip_addr) {
  308.             flag = 1;
  309.         }
  310.         reset_tcp(tcb);
  311.         pwait(NULL);                /* Let the RSTs go forth */
  312.  
  313.         if(flag) {
  314.             tcbtmp = Tcbs;
  315.         }
  316.     }
  317. }
  318.  
  319. void
  320. reset_tcp(struct tcb *tcb)
  321. {
  322.     if(tcb != NULLTCB) {
  323.         if(tcb->state != TCP_LISTEN && tcb->state != TCP_TIME_WAIT) {
  324.             struct tcp fakeseg;
  325.             struct ip fakeip;
  326.  
  327.             /* Compose a fake segment with just enough info to generate the
  328.              * correct RST reply
  329.              */
  330.             fakeseg.flags.rst = 0;
  331.             fakeseg.dest = tcb->conn.local.port;
  332.             fakeseg.source = tcb->conn.remote.port;
  333.             fakeseg.flags.ack = 1;
  334.             /* Here we try to pick a sequence number with the greatest likelihood
  335.              * of being in his receive window.
  336.              */
  337.             fakeseg.ack = tcb->snd.nxt + tcb->snd.wnd - 1;
  338.             fakeip.dest = tcb->conn.local.address;
  339.             fakeip.source = tcb->conn.remote.address;
  340.             fakeip.tos = tcb->tos;
  341.             reset(&fakeip,&fakeseg);
  342.         }
  343.         close_self(tcb,RESET);
  344.     }
  345. }
  346.  
  347.